﻿//Orginal date made: 26th March 2012
//Creator: by Luke Bermingham

//Last modified:
//Modifier name:

using System;
using System.Collections.Generic;
using System.Windows;

namespace SharedResources.Model
{
    public class SortedGroupedDataset
    {
        //this class represents the trajectory data grouped by ObjectId and then sorted by times
        //the times are sorted as they occur. i.e 9:01am, 9:02am, 9:03am...

        #region BoundingCoordinates

        //bounding parameters of the coordinates
        private double _maxX;
        public double MaxX { 
            get
            {
                if(Math.Abs(_maxX - 0.0) < Precision.EPSILON)
                {
                    throw new Exception("Max x has not been set, cannot get it yet.");
                }
                return _maxX;
            }
        }

        private double _minX;
        public double MinX
        {
            get
            {
                if (Math.Abs(_minX - 0.0) < Precision.EPSILON)
                {
                    throw new Exception("Min x has not been set, cannot get it yet.");
                }
                return _minX;
            }
        }

        private double _maxY;
        public double MaxY
        {
            get
            {
                if (Math.Abs(_maxY - 0.0) < Precision.EPSILON )
                {
                    throw new Exception("Max y has not been set, cannot get it yet.");
                }
                return _maxY;
            }
        }

        private double _minY;
        public double MinY
        {
            get
            {
                if (Math.Abs(_minY - 0.0) < Precision.EPSILON)
                {
                    throw new Exception("Min y has not been set, cannot get it yet.");
                }
                return _minY;
            }
        }
        
        public void SetBoundingCoordinates(double maxX, double maxY, double minX, double minY)
        {
            _maxX = maxX;
            _maxY = maxY;
            _minX = minX;
            _minY = minY;
        }

        #endregion


        private Dictionary<int, SortedList<DateTime, GeoCoordinate>> _groupedTrajectorySets;
        public Dictionary<int, SortedList<DateTime, GeoCoordinate>> GroupedTrajectorySets
        {
            get
            {
                if(_groupedTrajectorySets != null)
                {
                    return _groupedTrajectorySets;
                }
                _groupedTrajectorySets = new Dictionary<int, SortedList<DateTime, GeoCoordinate>>();
                return _groupedTrajectorySets;
            }
        }

        public SortedGroupedDataset()
        {
            //constructor setting up initial empty datastructure
            _groupedTrajectorySets = new Dictionary<int, SortedList<DateTime, GeoCoordinate>>();
            _visualisationPaths = new Dictionary<int, SortedList<DateTime, Point>>();
            
        }

        private Dictionary<int, SortedList<DateTime,Point>> _visualisationPaths;
        public Dictionary<int, SortedList<DateTime, Point>> VisualisationPaths
        {
            get
            {
                if (_visualisationPaths != null)
                {
                    return _visualisationPaths;
                }
                _visualisationPaths = new Dictionary<int, SortedList<DateTime, Point>>();
                return _visualisationPaths;
            }
        }

        public bool Add(SpatioTemporalPoint spatioTemporalPoint)
        {
            int currentObjectId = spatioTemporalPoint.ObjectId;

            if(_groupedTrajectorySets.ContainsKey(currentObjectId) && _visualisationPaths.ContainsKey(currentObjectId))
            {
                //alreayd contains the key and sortedlist
                //do some insertions
                SortedList<DateTime, GeoCoordinate> specificSortedTimeList; //is pass with out so is by reference, hence changing the original
                _groupedTrajectorySets.TryGetValue(currentObjectId, out specificSortedTimeList);
                if(specificSortedTimeList.ContainsKey(spatioTemporalPoint.DateTimeRecorded) == false) //so long as it isn;t a duplicate time key
                {
                    specificSortedTimeList.Add(spatioTemporalPoint.DateTimeRecorded, spatioTemporalPoint.SpatialData);
                    
                    _visualisationPaths[currentObjectId].Add(spatioTemporalPoint.DateTimeRecorded, CreateZeroBasedPoint(spatioTemporalPoint.SpatialData.Longitude, 
                        spatioTemporalPoint.SpatialData.Latitude)); //add time and new zero based point
                }
            }
            //does not contain the key, so make one
            else
            {
                try
                {
                    _groupedTrajectorySets.Add(currentObjectId,
                                               new SortedList<DateTime, GeoCoordinate> { { spatioTemporalPoint.DateTimeRecorded, spatioTemporalPoint.SpatialData } });

                    _visualisationPaths.Add(currentObjectId, new SortedList<DateTime, Point> { 
                    {spatioTemporalPoint.DateTimeRecorded, CreateZeroBasedPoint(spatioTemporalPoint.SpatialData.Longitude,
                                                              spatioTemporalPoint.SpatialData.Latitude)} });
                }
                catch (ArgumentException e)
                {
                    System.Diagnostics.Debug.WriteLine("Log: Tried to insert already existing time, "
                                                       + spatioTemporalPoint.DateTimeRecorded + "." + e.Message);
                    return false;
                }
            }             
            return true;
        }

        private Point CreateZeroBasedPoint(double longitude, double latitude) //x and y
        {
            double zeroBasedX = longitude - MinX; // so if got 23.5 as value and Min X is 20, new value 3.5
            double zeroBasedY = latitude - MinY;
            return new Point(zeroBasedX, zeroBasedY);
        }


    }
}
